package qrcode;

import java.util.Iterator;

public class NumericModeSequence implements QRSequence {

  private Version version;
  
  private String numbers;
  
  public NumericModeSequence(Version version, String numbers) {
    this.version = version;
    this.numbers = numbers;
  }

  @Override
  public Iterator<Boolean> iterator() {
    return new QRSequenceBitIterator(this);
  }

  @Override
  public ModeIndicator getModeIndicator() {
    return ModeIndicator.NUMERIC;
  }

  @Override
  public int getLengthInBits() {
    final int length = numbers.length();
    int r = 0;
    if (length % 3 == 1)
      r = 4;
    if (length % 3 == 2)
      r = 7;
    return 4 + getNumberOfBitsInCharacterCountIndicator() + 10 * (length / 3) + r;
  }

  @Override
  public Version getVersion() {
    return version;
  }

  public int getNumberOfBitsInCharacterCountIndicator() {
    int versionNr = version.getVersionNumber().intValue();
    if (versionNr <= 9)
      return 10;
    if (versionNr <= 26)
      return 12;
    return 14;
  }

  @Override
  public boolean getSequenceBit(final int idx) {
    if (idx < 4)
      return BitHelper.getBitAtStartingAtMostSignificant(getModeIndicator().asByte(), 4, idx);
    int tidx = idx - 4;
    if (tidx < getNumberOfBitsInCharacterCountIndicator()) {
      return BitHelper.getBitAtStartingAtMostSignificant(numbers.length(), getNumberOfBitsInCharacterCountIndicator(),
          tidx);
    }
    tidx -= getNumberOfBitsInCharacterCountIndicator();
    final int tripleCount = numbers.length() / 3;
    final int tripleIdx = tidx / 10;
    final int bidx = tidx % 10;
    if (tripleIdx == tripleCount){
      // remaining characters
      if (numbers.length()% 3 == 1){
        // one remaining character
        String remainder = numbers.substring(numbers.length()-1);
        int value = Integer.parseInt(remainder);
        return BitHelper.getBitAtStartingAtMostSignificant(value, 4, bidx);
      } else {
        // two remaining characters
        String remainder = numbers.substring(numbers.length()-2);
        int value = Integer.parseInt(remainder);
        return BitHelper.getBitAtStartingAtMostSignificant(value, 7, bidx);
      }
    } else {
      // encode triple
      String triple = numbers.substring(tripleIdx*3, tripleIdx*3+3);
      int value = Integer.parseInt(triple);
      return BitHelper.getBitAtStartingAtMostSignificant(value, 10, bidx);
    }
  }
  
  /**
   * <pre>
   * 0001 0000000110 0000001100 0101011001
   * 0001 0000000111 0000001100 0101011001 0110
   * 0001 0000001000 0000001100 0101011001 1000011
   * mode le=8               12        345      67
   * </pre
   */
  public static void main(String[] args) {
    NumericModeSequence seq = new NumericModeSequence(Version.VERSION_1, "01234567");
    for (boolean b:seq){
      System.out.print(b?'1':'0');
    }
  }
}